/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/

const PromiseStatus = {
  PENDING: 'pending',
  FULFILLED: 'fulfilled',
  REJECTED: 'rejected'
};

class _Promise {

  /** Promsie的默认状态 **/
  #status = PromiseStatus.PENDING;

  /** 成功后的值 **/
  #value = undefined;

  /** 失败后的原因 **/
  #reason = undefined;

  /** 
   * 成功后回调 
   * 能够多次调用
   **/
  #succCallback = [];

  /** 
   * 失败的回调 
   * 能够多次调用
   **/
  #failedCallback = [];

  constructor(executor) {

    /** 首次调用执行器错误就抛出异常 **/
    try {
      /** 立即执行的执行器 **/
      executor(this.#resovle, this.#reject);
    } catch (error) {
      this.#reject(error);
    }

  };

  /**
   * @param {*} promiseAll []
   * @return Promise
   * @desc 迭代promiseAll中的元素，按顺序成功后返回
   */
  static all = (promiseAll) => {
    const result = [];
    const len = promiseAll?.length;
    let recordProgress = 0;
    return new _Promise((resolve, reject) => {

      const addData = (index, value) => {
        result[index] = value;
        recordProgress++
        /** resolve之前要处理异步情况 **/
        if (recordProgress === len) {
          resolve(result);
        }
      }

      let count = 0;
      try {
        // 遍历执行每个元素
        while (count < len) {
          const curr = promiseAll[count];
          // 判断是否为promise对象
          if (curr instanceof _Promise) {
            // 使用while循环，异步就会出现顺序不同步的问题，只能缓存一下这个索引值
            const index = count;
            curr.then(
              value => addData(index, value),
              reason => reject(reason)
            );

          } else {
            addData(count, curr)
          };
          count++
        };
      } catch (error) {
        reject(new TypeError('传入的值不是数组'));
      }
    });
  }

  static resolve = value => {
    return value instanceof _Promise ?
      value :
      new _Promise(resolve => resolve(value));
  }

  static reject = reason => {
    return reason instanceof _Promise ?
      reason :
      new _Promise((r, reject) => reject(reason))
  }

  #resovle = value => {
    if (this.#isPromiseStatusPending()) return;

    // 改变promise状态为成功
    this.#status = PromiseStatus.FULFILLED;

    // 保存成功后的值
    this.#value = value;

    // 成功回调存在就调用
    while (this.#succCallback.length) {
      this.#succCallback.shift()();
    };
  };

  #reject = reason => {
    if (this.#isPromiseStatusPending()) return;

    // 改变promise状态为失败
    this.#status = PromiseStatus.REJECTED

    // 保存失败后的原因
    this.#reason = reason;

    // 失败回调存在就调用
    while (this.#failedCallback.length) {
      this.#failedCallback.shift()();
    }
  };

  /** 
   * 判断当前的状态是成功还是失败
   * 执行对应的回调函数 
   **/
  then = (succCallback, failedCallback) => {

    /** then方法不传递参数，状态向下传递 **/
    succCallback = succCallback || (value => value);
    failedCallback = failedCallback || (reason => reason);

    const returnPromise = new _Promise((resolve, reject) => {

      // 执行器立执行
      if (this.#status === PromiseStatus.FULFILLED) {

        setTimeout(() => {
          try {
            const returnThen = succCallback(this.#value);
            /**
             * 确认returnThen的类型
             * 1、普通类型 直接resolve
             * 2、promise类型，等待结果在确认是调用resolve还是reject
             */
            this.#resolvePromise(returnPromise, returnThen, resolve, reject);
          } catch (error) {
            /** 把错误传递到下一次回调 **/
            reject(error);
          }
        }, 0);

      } else if (this.#status === PromiseStatus.REJECTED) {
        setTimeout(() => {
          try {
            const returnThen = failedCallback(this.#reason);

            /**
             * 确认returnThen的类型
             * 1、普通类型 直接reject
             * 2、promise类型，等待结果在确认是调用resolve还是reject
             */
            this.#resolvePromise(returnPromise, returnThen, resolve, reject);
          } catch (error) {
            /** 把错误传递到下一次回调 **/
            reject(error);
          }
        }, 0);
      } else {
        // 等待的状态，异步的情况
        // 存储成功或失败的回调
        this.#succCallback.push(() => {
          setTimeout(() => {
            try {
              const returnThen = succCallback(this.#value);

              /**
               * 确认returnThen的类型
               * 1、普通类型 直接resolve
               * 2、promise类型，等待结果在确认是调用resolve还是reject
               */
              this.#resolvePromise(returnPromise, returnThen, resolve, reject);
            } catch (error) {
              /** 把错误传递到下一次回调 **/
              reject(error);
            }
          }, 0);
        });
        this.#failedCallback.push(() => {
          setTimeout(() => {
            try {
              const returnThen = failedCallback(this.#reason);

              /**
               * 确认returnThen的类型
               * 1、普通类型 直接reject
               * 2、promise类型，等待结果在确认是调用resolve还是reject
               */
              this.#resolvePromise(returnPromise, returnThen, resolve, reject);
            } catch (error) {
              /** 把错误传递到下一次回调 **/
              reject(error);
            }
          }, 0);
        });
      };
    });

    return returnPromise;
  };

  finally = (finallyCallback) => {
    /** 不管什么状态都会触发finally **/
    return this.then((value) => {
      /** 等待回调先完成后再reutrn **/
      return _Promise.resolve(finallyCallback()).then(() => value);
    }, (reason) => {
      return _Promise.resolve(finallyCallback()).then(() => {throw reason});
    })
  };

  catch = (catchCallback) => {
    return this.then(undefined, catchCallback);
  };

  /** 
   * Promise状态从pending --> fulfilled 或 rejected后不可更改 
   * 改变后的状态为不可逆
   * 判断status状态不为等待状态后，阻止成功或失败的回调执行
   */
  #isPromiseStatusPending = () => {
    return this.#status !== PromiseStatus.PENDING;
  };

  #resolvePromise = (returnPromise, returnThen, resolve, reject) => {

    /** 构造的promise是否与return的promise相等 **/
    if (returnPromise === returnThen) {
      return reject(new TypeError('Promise-chain cycle'))
    }

    /** 成功或失败的回调值是否为promise **/
    if (returnThen instanceof _Promise) {
      returnThen.then(resolve, reject);
    } else {
      resolve(returnThen);
    }
  }
};

module.exports = _Promise;